package com.zan.zanchat.common.user.service.impl;

import com.zan.zanchat.common.common.annotation.RedissonLock;
import com.zan.zanchat.common.common.service.LockService;
import com.zan.zanchat.common.user.dao.UserBackpackDao;
import com.zan.zanchat.common.user.domain.entity.UserBackpack;
import com.zan.zanchat.common.user.domain.enums.IdempotentEnum;
import com.zan.zanchat.common.user.service.IUserBackpackService;
import com.zan.zanchat.common.user.service.adapter.UserAdapter;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @Author Zan
 * @Create 2024/3/17 10:41
 * @Description :
 */
@Service
public class UserBackpackServiceImpl implements IUserBackpackService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private UserBackpackDao userBackpackDao;

    @Resource
    private LockService lockService;

    @Resource
    @Lazy
    private UserBackpackServiceImpl userBackpackService;

    @Override
    public void acquireItem(Long uid, Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        String idempotent = getIdempotent(itemId, idempotentEnum, businessId);
        // 1.第一种方法：使用注入自己，防止同步调用，进行调用，但是要防止循环注入，可以添加@Lazy注解（习惯于这种）
        userBackpackService.doAcquireItem(uid, itemId, idempotent);
        // 2.第二种方法：使用Spring的Aop
//        ((UserBackpackServiceImpl) AopContext.currentProxy()).doAcquireItem(uid, itemId, idempotent);
        /**
         * 原始写法
         */
        /*
        // 创建分布式锁
        RLock lock = redissonClient.getLock("acquireItem" + idempotent);
        boolean b = lock.tryLock(); // 加锁 - 锁可用为true
        AssertUtil.isTrue(b, "请求太频繁了");
        try {
            // 判断幂等是否存在
            UserBackpack userBackpack = userBackpackDao.getByIdempotent(idempotent);
            if (Objects.nonNull(userBackpack)) {
                // 存在
                return;
            }
            // 发放物品
            UserBackpack insertUserBackpack = UserAdapter.buildUserBackpackResp(uid, itemId, idempotent);
            userBackpackDao.save(insertUserBackpack);
        } finally {
            lock.unlock(); // 解锁
        }*/
    }

    /**
     * 真实的发放物品接口
     */
    @Transactional // 当进行同步调用的时候，会导致切面不生效，我们想要去使用事务的话，必须得去Spring那边去调用
    @RedissonLock(key = "#idempotent", waitTime = 5000)
    public void doAcquireItem(Long uid, Long itemId, String idempotent) {
        /**
         * 自定义封装分布式锁 - 注解式
         */
        // 判断幂等是否存在
        UserBackpack userBackpack = userBackpackDao.getByIdempotent(idempotent);
        if (Objects.nonNull(userBackpack)) {
            // 存在
            return;
        }
        // todo 业务的检查 - 一个人相同的徽章只发一次

        // 发放物品
        UserBackpack insertUserBackpack = UserAdapter.buildUserBackpackResp(uid, itemId, idempotent);
        userBackpackDao.save(insertUserBackpack);
    }

    /**
     * 构建自定义幂等号
     */
    private String getIdempotent(Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        return String.format("%d_%d_%s", itemId, idempotentEnum.getType(), businessId);
    }

}
